/*条件变量*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> 
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>

typedef int datatype;
typedef struct listnode
{
	datatype data;
	struct listnode *next;
} list_node, *list_pnode;

/*全局变量*/
pthread_mutex_t mutex;
pthread_cond_t cond;
list_pnode head = NULL;
int count = 0;//节点数

/*函数声明*/
extern void init_linklist(list_pnode *H);
extern void insert_linklist(list_pnode pnode, list_pnode new_pnode);
extern void show_linklist(list_pnode head);
extern void remove_linklist(list_pnode pnode);
extern bool isempty_linklist(list_pnode pnode);

/*线程1：每500ms插入一个节点*/
void* producer(void* arg)
{
	int n = 20;
	datatype data;
	
	usleep(10000);//10ms，保证先让线程2进入等待队列
	while(n--)
	{
		pthread_mutex_lock(&mutex);//上锁
		srand((unsigned int)time(NULL));
		data = rand()%100+1;//data是1~100的随机数
		list_pnode pnew = (list_pnode)malloc(sizeof(list_node));
		pnew->data = data;
		insert_linklist(head,pnew);
		count++;
		show_linklist(head);
		printf("节点个数：%d\n",count);
		pthread_cond_signal(&cond);//通知并唤醒线程
		pthread_mutex_unlock(&mutex);//解锁
		
		usleep(500000);//500ms
	}
	
	return NULL;
}

/*线程2：线程1插入后就立刻取走*/
void* consumer(void* arg)
{
	int n = 20;

	while(n--)
	{
		pthread_mutex_lock(&mutex);//上锁
		pthread_cond_wait(&cond, &mutex);//等待条件成立
		remove_linklist(head);
		count--;
		show_linklist(head);
		printf("节点个数：%d\n",count);
		pthread_mutex_unlock(&mutex);//解锁
	}

	return NULL;
}

int main(void)
{
	/*初始化链表*/
	init_linklist(&head);

	/*初始化互斥锁和条件变量*/
	pthread_mutex_init(&mutex,NULL);
	pthread_cond_init(&cond,NULL);
	
	/*创建线程1、2*/
	pthread_t tid1,tid2;	
	pthread_create(&tid1,NULL,producer,NULL);
	pthread_create(&tid2,NULL,consumer,NULL);
	
	/*等待子线程结束并回收*/
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	
	/*销毁互斥锁和条件变量*/
	pthread_mutex_destroy(&mutex);
	pthread_cond_destroy(&cond);

	return 0;
}

//1.初始化
void init_linklist(list_pnode *H)
{
	*H = (list_pnode)malloc(sizeof(list_node)); //创建头节点
	if (*H == NULL) {
		perror("malloc");
		exit(1);
	}
	(*H)->next = NULL;
}

//2.插入节点, pnode:插入位置前一个节点的指针, new_pnode:要插入的节点指针
//不管是头尾中间,只要有前一个节点的指针都可以插入
void insert_linklist(list_pnode pnode, list_pnode new_pnode)
{
	new_pnode->next = pnode->next;
	pnode->next = new_pnode;
}

//3.遍历,只要有头指针就能遍历
void show_linklist(list_pnode head) 
{
	list_pnode pnode;
	printf("[head]");
	for (pnode = head->next; pnode != NULL ; pnode = pnode->next) 
		printf("--> %d", pnode->data);
	printf("--> NULL\n");
}

//4.删除节点 删除pnode指向的后面的节点
void remove_linklist(list_pnode pnode)
{
	list_pnode ptmp;
	//判断链表是否为空,如果pnode->next是空就没有节点不能删除
	if (isempty_linklist(pnode)) {
		printf("链表为空,不能删除!\n");
		return ;
	}
	ptmp = pnode->next; //找到要删除的节点
	pnode->next = ptmp->next;
	free(ptmp);
}

bool isempty_linklist(list_pnode pnode)
{
	if (pnode->next == NULL) 
		return true;
	else 
		return false;
}


